﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Reflection;
using System.Resources;
using System.Windows.Controls;

namespace CAION2.Helpers
{
    class Culture
    {
        private void LoadResources(ComponentResourceManager rm, CultureInfo culture, SortedList<string, object> resources)
        {
            if (!culture.Equals(CultureInfo.InvariantCulture))
            {
                LoadResources(rm, culture.Parent, resources);
            }
            ResourceSet resourceSet = rm.GetResourceSet(culture, true, true);
            if (resourceSet != null)
            {
                foreach (DictionaryEntry entry in resourceSet)
                {
                    resources[(string)entry.Key] = entry.Value;
                }
            }
        }

        protected static bool IsVBAssembly(Assembly assembly)
        {
            AssemblyName[] referencedAssemblies = assembly.GetReferencedAssemblies();
            foreach (AssemblyName refAssembly in referencedAssemblies)
            {
                if (refAssembly.Name == "Microsoft.VisualBasic")
                    return true;
            }
            return false;
        }

        protected virtual bool IsExcluded(string componentName, string propertyName)
        {
            string resourceName = componentName + "." + propertyName;
            foreach (string value in _excludeProperties)
            {
                if (value.Contains("."))
                {
                    if (resourceName.Contains(value)) return true;
                }
                else
                {
                    // backward compatibility with previous versions that could only exclude
                    // based on the property name
                    //
                    if (value == propertyName) return true;
                }
            }
            if (ExcludeResource != null)
            {
                return ExcludeResource(componentName, propertyName);
            }
            return false;
        }

        protected virtual void ApplyResources(Type componentType,
                                              Component instance,
                                              CultureInfo culture)
        {
            System.IO.Stream resourceStream 
                = componentType.Assembly.GetManifestResourceStream(componentType.FullName 
                     + ".resources");
            if (resourceStream == null) return;
            
            Type parentType = componentType.BaseType;
            if (parentType != null)
            {
                ApplyResources(parentType, instance, culture);
            }

            ComponentResourceManager resourceManager 
                = new ComponentResourceManager(componentType);
            SortedList<string, object> resources = new SortedList<string, object>();
            LoadResources(resourceManager, culture, resources);

            Dictionary<string, Component> components = new Dictionary<string, Component>();

            Dictionary<Type, IExtenderProvider> extenderProviders = new Dictionary<Type, IExtenderProvider>();

            bool isVB = IsVBAssembly(componentType.Assembly);

            components["$this"] = instance;
            FieldInfo[] fields = componentType.GetFields(BindingFlags.Instance | 
                                                         BindingFlags.NonPublic | 
                                                         BindingFlags.Public);
            foreach (FieldInfo field in fields)
            {
                string fieldName = field.Name;
        
                if (isVB)
                {
                    fieldName = fieldName.Substring(1, fieldName.Length - 1);
                }
                
                string resourceName = ">>" + fieldName + ".Name";
                if (resources.ContainsKey(resourceName))
                {
                    Component childComponent = field.GetValue(instance) as Component;
                    if (childComponent != null)
                    {
                        components[fieldName] = childComponent;

                        ApplyResources(childComponent.GetType(), childComponent, culture);

                        if (childComponent is IExtenderProvider)
                        {
                            extenderProviders[childComponent.GetType()] 
                                = childComponent as IExtenderProvider;
                        }
                    }
                }
            }

            foreach (KeyValuePair<string, object> pair in resources)
            {
                string resourceName = pair.Key;
                object resourceValue = pair.Value;
                string[] resourceNameParts = resourceName.Split('.');
                string componentName = resourceNameParts[0];
                string propertyName = resourceNameParts[1];

                if (componentName.StartsWith(">>")) continue;
                if (IsExcluded(componentName, propertyName)) continue;

                Component component = null;
                if (!components.TryGetValue(componentName, out component)) continue;

                // some special case handling for control sizes/locations
                //
                Control control = component as Control;
                if (control != null)
                {
                    switch (propertyName)
                    {
                       case "AutoScaleDimensions":
                           SetAutoScaleDimensions(control as ContainerControl, (SizeF)resourceValue);
                           continue;
                       case "Size":
                           SetControlSize(control, (Size)resourceValue);
                           continue;
                       case "Location":
                           SetControlLocation(control, (Point)resourceValue);
                           continue;
                       case "Padding":
                       case "Margin":
                           resourceValue = AutoScalePadding((Padding)resourceValue);
                           break;
                       case "ClientSize":
                           if (control is Form && PreserveFormSize) continue;
                           resourceValue = AutoScaleSize((Size)resourceValue);
                           break;
                     }
                }

                // use the property descriptor to set the resource value
                //
                PropertyDescriptor pd 
                    = TypeDescriptor.GetProperties(component).Find(propertyName, false);
                if (((pd != null) && !pd.IsReadOnly) && 
                   ((resourceValue == null) || pd.PropertyType.IsInstanceOfType(resourceValue)))
                {
                    pd.SetValue(component, resourceValue);
                }
                else 
                {
                    // there was no property corresponding to the given resource name.  
                    // If this is a control the property may be an extender property so 
                    // try applying it as an extender resource
                    //
                    if (control != null)
                    {
                        ApplyExtenderResource(extenderProviders, 
                                              control, propertyName, resourceValue);
                    }
                }
            }
        }
    }
}
